package link

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/util/gconv"
	"github.com/gomodule/redigo/redis"
	"github.com/tebeka/selenium"
	"github.com/xuri/excelize/v2"
	"image"
	"image/png"
	"io/ioutil"
	"linkable_spider/utils"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"
)

type Detail struct {
	Title       string `json:"title"`
	Url         string `json:"url"`
	Dir         string `json:"dir"`
	ImageBase64 string `json:"image_base64"`
	Img         string `json:"img"`
}

// 登录获取cookie

func LoginGetCookie1() *utils.Account {
	port := utils.RedisGetValidPort()
	_, webDriverLogin, err := utils.GetWebDriver(utils.RedisGetValidPort())
	defer utils.RedisReleasePort(port)
	defer webDriverLogin.Quit()
	if err != nil {
		fmt.Println("GetWebDriver err : ", err)
		log.Fatal("反爬虫机制触发,wait 10 minutes")

	}

	loginUrl := "https://linkable.partcommunity.com/3d-cad-models/sso/"

	err = webDriverLogin.Get(loginUrl)
	if err != nil {
		fmt.Println("webDriver.Get err : ", err)
	}
	utils.RandomSleep()

	account := utils.RandAccount()

	inputEmail, err := webDriverLogin.FindElement(selenium.ByXPATH, "//input[@id='j_username']")
	if err != nil {
		fmt.Println("inputEmail err : ", err)
		log.Fatal("反爬虫机制触发,wait 10 minutes")
	}
	err = inputEmail.SendKeys(account.Email)
	if err != nil {
		fmt.Println("inputEmail.SendKeys err : ", err)
	}

	cookieButton, err := webDriverLogin.FindElement(selenium.ByXPATH, "//input[@class='ui-button cnsButton cookie-settings-accept-button']")
	if err == nil || cookieButton != nil {
		cookieButton.Click()
	}

	utils.RandomSleep()

	nextButton, err := webDriverLogin.FindElement(selenium.ByXPATH, "//button[@class='ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only cnsButtonImportant Mtop0_4 IT-continue-login']")

	if err != nil || nextButton == nil {
		fmt.Println("nextButton err : ", err)
		return nil
	}

	maxRetries := 5
	retryCount := 0

	for retryCount < maxRetries {
		err := nextButton.Click()
		utils.RandomSleep()

		if err != nil {
			fmt.Println("nextButton.Click err:", err)
			retryCount++
			continue
		}

		inputPassword, err := webDriverLogin.FindElement(selenium.ByXPATH, "//input[@id='j_password']")
		if err != nil || inputPassword == nil {
			if err != nil {
				fmt.Println("not j_password err:", err)
				retryCount++
				continue
			}
		}

		// 点击成功，跳出循环
		break
	}

	if retryCount == maxRetries {
		fmt.Println("点击操作失败次数过多")
		//log.Fatal("反爬虫机制触发，等待 10 分钟")
		return nil
	}

	utils.RandomSleep()

	inputPassword, err := webDriverLogin.FindElement(selenium.ByXPATH, "//input[@id='j_password']")
	if err != nil {
		fmt.Println("inputPassword err:", err)
	}
	err = inputPassword.SendKeys(account.Password)
	if err != nil {
		fmt.Println("写入密码失败")
	}
	utils.RandomSleep()

	loginButton, err := webDriverLogin.FindElement(selenium.ByXPATH, "//button[@id='JSloginBtn']")
	if err != nil {
		fmt.Println("loginButton err:", err)
		return nil
	}

	err = loginButton.Click()
	if err != nil {
		return nil
	}

	utils.RandomSleep()

	// 获取cookie
	cookies, err := webDriverLogin.GetCookies()
	if err != nil {
		fmt.Println("GetCookies err : ", err)
	}
	fmt.Println("cookies : ", cookies)

	if len(cookies) < 3 {
		fmt.Println("登录失败")
		return nil
	}

	account.Cookie = cookies
	account.Email = account.Email

	return account
}

func LoginGetCookie() *utils.Account {
	port := utils.RedisGetValidPort()
	_, webDriverLogin, err := utils.GetWebDriver(utils.RedisGetValidPort())
	defer utils.RedisReleasePort(port)
	defer webDriverLogin.Quit()
	if err != nil {
		fmt.Println("GetWebDriver err : ", err)
		log.Fatal("反爬虫机制触发,wait 10 minutes")

	}

	loginAttempts := 0
	maxLoginAttempts := 3

	for loginAttempts < maxLoginAttempts {

		loginUrl := "https://linkable.partcommunity.com/3d-cad-models/sso/"

		err = webDriverLogin.Get(loginUrl)
		if err != nil {
			fmt.Println("webDriver.Get err : ", err)
		}
		utils.RandomSleep()

		account := utils.RandAccount()

		inputEmail, err := webDriverLogin.FindElement(selenium.ByXPATH, "//input[@id='j_username']")
		if err != nil {
			fmt.Println("inputEmail err : ", err)
			log.Fatal("反爬虫机制触发,wait 10 minutes")
		}
		err = inputEmail.SendKeys(account.Email)
		if err != nil {
			fmt.Println("inputEmail.SendKeys err : ", err)
		}

		cookieButton, err := webDriverLogin.FindElement(selenium.ByXPATH, "//input[@class='ui-button cnsButton cookie-settings-accept-button']")
		if err == nil || cookieButton != nil {
			cookieButton.Click()
		}

		utils.RandomSleep()

		nextButton, err := webDriverLogin.FindElement(selenium.ByXPATH, "//button[@class='ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only cnsButtonImportant Mtop0_4 IT-continue-login']")

		if err != nil || nextButton == nil {
			fmt.Println("nextButton err : ", err)
			return nil
		}

		maxRetries := 5
		retryCount := 0

		for retryCount < maxRetries {
			err := nextButton.Click()
			utils.RandomSleep()

			if err != nil {
				fmt.Println("nextButton.Click err:", err)
				retryCount++
				continue
			}

			inputPassword, err := webDriverLogin.FindElement(selenium.ByXPATH, "//input[@id='j_password']")
			if err != nil || inputPassword == nil {
				if err != nil {
					fmt.Println("not j_password err:", err)
					retryCount++
					continue
				}
			}

			// 点击成功，跳出循环
			break
		}

		if retryCount == maxRetries {
			fmt.Println("点击操作失败次数过多")
			//log.Fatal("反爬虫机制触发，等待 10 分钟")
			return nil
		}

		utils.RandomSleep()

		inputPassword, err := webDriverLogin.FindElement(selenium.ByXPATH, "//input[@id='j_password']")
		if err != nil {
			fmt.Println("inputPassword err:", err)
		}
		err = inputPassword.SendKeys(account.Password)
		if err != nil {
			fmt.Println("写入密码失败")
		}
		utils.RandomSleep()

		loginButton, err := webDriverLogin.FindElement(selenium.ByXPATH, "//button[@id='JSloginBtn']")
		if err != nil {
			fmt.Println("loginButton err:", err)
			return nil
		}

		err = loginButton.Click()
		if err != nil {
			return nil
		}

		utils.RandomSleep()

		// 获取cookie
		cookies, err := webDriverLogin.GetCookies()
		if err != nil {
			fmt.Println("GetCookies err : ", err)
		}
		fmt.Println("cookies : ", cookies)

		if len(cookies) < 3 {
			fmt.Println("登录失败，正在重试...")
			loginAttempts++
			continue
		}

		account.Cookie = cookies
		account.Email = account.Email

		return account
	}

	fmt.Println("登录失败")
	return nil
}

// 获取列表 （除了一级列表）

func GetLinkableList() {

	account := LoginGetCookie()
	if account == nil {
		fmt.Println("LINKABLE列表[登录失败]: ")
	}

	port := utils.RedisGetValidPort()
	_, webDriver, err := utils.GetWebDriver(utils.RedisGetValidPort())
	defer utils.RedisReleasePort(port)
	defer webDriver.Quit()
	if err != nil {
		fmt.Println("GetWebDriver err : ", err)
		log.Fatal("反爬虫机制触发,wait 10 minutes")

	}
	url := "https://linkable.partcommunity.com/3d-cad-models/sso/"
	err = webDriver.Get(url)
	if err != nil {
		fmt.Println("加载页面失败 : ", err)
	}

	for _, v := range account.Cookie {
		cookie := v
		err = webDriver.AddCookie(&cookie)
		if err != nil {
			fmt.Println("AddCookie err : ", err)
		}
	}
	utils.RandomSleep()

	err = webDriver.Get(url)
	if err != nil {
		fmt.Println("加载页面失败 : ", err)
	}
	// 获取cookie
	cookies, err := webDriver.GetCookies()
	if err != nil {
		fmt.Println("GetCookies err : ", err)
	}
	//fmt.Println("cookies : ", cookies)
	//
	//var accountCookie utils.AccountCookie
	account.Cookie = cookies
	//accountCookie.Email = account.Email
	//text, _ := json.Marshal(accountCookie)
	//utils.SetAccountCookieToRedis(account.Email, gconv.String(text))

	utils.RandomSleep()

	elements, err := webDriver.FindElements(selenium.ByXPATH, "//div[@id='catalogSelection']//a")
	if err != nil {
		return
	}

	for i, element := range elements {
		url, err := element.GetAttribute("href")
		if err != nil {
			fmt.Println("获取链接失败 : ", err)
		}
		fmt.Println("i : ", i)
		fmt.Println("url : ", url)

		labelItem, _ := element.FindElement(selenium.ByXPATH, ".//label[@class='item-name']")
		labelText, _ := labelItem.Text()

		utils.SetFirstLevelUrlToRedis(labelText, url)
	}

}

//获取详情

func GetDetail(url string) error {
	status, _ := utils.RedisGetItemStatus(url)
	if status == utils.URL_STATUS_CRAWLED || status == utils.URL_STATUS_UNCRAWLED {
		fmt.Println("LINKABLE详情[跳过下载]:" + " url :" + url + " 已经处理或正在处理中")
		return nil
	}

	fmt.Println("LINKABLE详情[处理详情]: " + " url :" + url)
	utils.RedisSetItemStatus(url, utils.URL_STATUS_PROCESSING)

	account := LoginGetCookie()

	if account == nil {
		fmt.Println("LINKABLE详情[登录失败]: url:"+url, " account : ", account)
		utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
		return errors.New("LINKABLE详情[登录失败]: ")
	}

	cookies := account.Cookie
	port := utils.RedisGetValidPort()
	_, webDriver, err := utils.GetWebDriver(utils.RedisGetValidPort())
	defer utils.RedisReleasePort(port)
	if err != nil {
		fmt.Println("LINKABLE详情[处理失败]: " + " url :" + url)
		utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
		log.Fatal("反爬虫机制触发,wait 10 minutes")

	}

	indexUrl := "https://linkable.partcommunity.com/3d-cad-models/sso/"
	err = webDriver.Get(indexUrl)
	if err != nil {
		fmt.Println("LINKABLE详情[页面加载失败]: "+" url :"+url+" err : ", err)
		utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)

	}
	for _, v := range cookies {
		cookie := v
		webDriver.AddCookie(&cookie)
	}
	utils.RandomSleep()

	//进页面
	err = webDriver.Get(url)

	cookies, _ = webDriver.GetCookies()
	if err != nil {
		fmt.Println("LINKABLE详情[页面加载失败]: "+" url :"+url+" err : ", err)
		utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
	}

	// 页面最大化
	webDriver.MaximizeWindow("")

	//检查今日下载次数
	ticketsItem, err := webDriver.FindElement(selenium.ByXPATH, "//div[@class='cns-message-box']//span[@class='icon-label']")
	if err == nil && ticketsItem != nil {
		ticketsText, _ := ticketsItem.Text()
		if strings.Contains(ticketsText, "All of 50 download tickets used. No new ticket available until") {
			utils.DelAccountFromRedis(account.Email)
			fmt.Println("LINKABLE详情[今日下载次数已经用完]: " + " url :" + url)
			//utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
			//return nil

			account = LoginGetCookie()
			if account == nil {
				fmt.Println("LINKABLE详情[登录失败]: url:"+url, " account : ", account)
				utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
				return errors.New("LINKABLE详情[登录失败]: ")
			}

			for _, v := range account.Cookie {
				cookie := v
				webDriver.AddCookie(&cookie)
			}
		}
	}
	utils.RandomSleep()

	//分类目录作为文件夹名称
	dirList, err := webDriver.FindElements(selenium.ByXPATH, "//div[@class='part-details']//ol/li//span")
	if err != nil {
		fmt.Println("dir加载失败: ", err)
	}

	var path string
	for _, dir := range dirList {
		dirText, _ := dir.Text()
		fmt.Println("dirText : ", dirText)

		path = filepath.Join(path, dirText)
	}

	fmt.Println("path : ", path)
	//获取文件名称
	NameItem, err := webDriver.FindElement(selenium.ByXPATH, "//h1[@class='part-nb']")
	if err != nil {
		fmt.Println("titleItem err : ", err)
		utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
		return err
	}
	name, err := NameItem.Text()
	if err != nil {
		fmt.Println("LINKABLE详情[获取文件名称失败]: "+" url :"+url+" err : ", err)
		utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
		return err
	}

	path = filepath.Join(path, name)

	webDriver.Quit()

	dir := utils.WeekTime(path)

	//下载文件
	port = utils.RedisGetValidPort()
	_, webDownloadDriver, err := utils.GetWebDriverDownload(utils.RedisGetValidPort(), dir)
	defer utils.RedisReleasePort(port)
	defer webDownloadDriver.Quit()
	if err != nil {
		fmt.Println("GetWebDownloadDriver err : ", err)

	}

	webDownloadDriver.Get(url)

	for _, v := range cookies {
		cookie := v
		webDownloadDriver.AddCookie(&cookie)
	}
	utils.RandomSleep()

	webDownloadDriver.Get(url)

	err = webDownloadDriver.MaximizeWindow("")
	if err != nil {
		fmt.Println("webDownloadDriver.MaximizeWindow err : ", err)
	}

	cookieButton, err := webDownloadDriver.FindElement(selenium.ByXPATH, "//input[@id='j_id_4w']")
	if err == nil || cookieButton != nil {
		cookieButton.Click()
	}

	utils.RandomSleep()

	CADButton, err := webDownloadDriver.FindElement(selenium.ByXPATH, "//div[@class='cns-flex-container cns-flex-responsive CUST_AREA_GenerationButtons']//button")
	if err != nil {
		fmt.Println("CADButton err : ", err)
	}
	err = CADButton.Click()
	if err != nil {
		fmt.Println("CADButton.Click err : ", err)
	}

	script1 := `return document.getElementById("topMessage-detail").textContent;`
	topMessageItem1, err := webDownloadDriver.ExecuteScript(script1, nil)

	if err != nil {
		// 处理执行JavaScript代码的错误
		fmt.Println("执行JavaScript代码失败:", err)

	}
	if strings.Contains(topMessageItem1.(string), "当前已达到下载限额，请参考许可协议中的使用条款。") {
		fmt.Println("topMessageItem : ", topMessageItem1)
		fmt.Println("LINKABLE资源[今日下载次数已经用完!!!!!]: " + " url :" + url)
		utils.DelAccountFromRedis(account.Email)
		//utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
		//return errors.New("LINKABLE资源[今日下载次数已经用完!!!!!]: " + " url :" + url)
		account = LoginGetCookie()

		if account == nil {
			fmt.Println("LINKABLE资源[登录失败]: url:"+url, " account : ", account)
			utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
			return errors.New("LINKABLE资源[登录失败]: ")
		}

		for _, v := range account.Cookie {
			cookie := v
			webDownloadDriver.AddCookie(&cookie)
		}

	}

	utils.RandomSleep()

	//资源不能免费下载
	crawledItem, err := webDownloadDriver.FindElement(selenium.ByXPATH, "//div[@id='crawled-part-form:crawled-part-dialog']//p[@class='Mtop1px']")

	if err == nil && crawledItem != nil {
		//这个资源不能免费下载
		crawledText, _ := crawledItem.Text()
		if strings.Contains(crawledText, "This catalog was") {

			fmt.Println("这个资源不能免费下载")
			utils.RedisSetItemStatus(url, utils.URL_STATUS_UNCRAWLED)
			//删除文件夹
			err := os.RemoveAll(dir)
			if err != nil {
				fmt.Println("删除文件夹失败 : ", err)
			}
			return errors.New("这个资源不能免费下载")
		}

	}

	utils.RandomSleep()

	tableItems, _ := webDownloadDriver.FindElements(selenium.ByXPATH, "//tbody[@id='CC10:catalog-table-grid_frozenTbody']//tr")

	counts := len(tableItems)
	isDownload := false

	for i := 0; i < counts; i++ {

		XPath := fmt.Sprintf("//tbody[@id='CC10:catalog-table-grid_frozenTbody']//tr[@data-ri='%d']//td//span", i)

		radioItem, err := webDownloadDriver.FindElement(selenium.ByXPATH, XPath)
		if err != nil {
			fmt.Println("radioItem err : ", err)
		}

		//radioItem, _ := tableItems[i].FindElement(selenium.ByXPATH, ".//td//span")
		utils.RandomSleep()

		text, _ := radioItem.Text()

		fmt.Println("text : ", text)

		err = radioItem.Click()
		if err != nil {
			fmt.Println("tableItem.Click err : ", err)
		}
		utils.RandomSleep()
		CADButton, err := webDownloadDriver.FindElement(selenium.ByXPATH, "//div[@class='cns-flex-container cns-flex-responsive CUST_AREA_GenerationButtons']//button")
		if err != nil {
			fmt.Println("CADButton err : ", err)
		}
		err = CADButton.Click()
		if err != nil {
			fmt.Println("CADButton.Click err : ", err)
		}

		script1 = `return document.getElementById("topMessage-detail").textContent;`
		topMessageItem1, err = webDownloadDriver.ExecuteScript(script1, nil)

		if err != nil {
			// 处理执行JavaScript代码的错误
			fmt.Println("执行JavaScript代码失败:", err)

		}
		if strings.Contains(topMessageItem1.(string), "当前已达到下载限额，请参考许可协议中的使用条款。") {
			fmt.Println("topMessageItem : ", topMessageItem1)
			fmt.Println("LINKABLE资源[今日下载次数已经用完!!!!!]: " + " url :" + url)
			utils.DelAccountFromRedis(account.Email)
			//utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
			//return errors.New("LINKABLE资源[今日下载次数已经用完!!!!!]: " + " url :" + url)
			account = LoginGetCookie()
			if account == nil {
				fmt.Println("LINKABLE资源[登录失败]: url:"+url, " account : ", account)
				utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
				return errors.New("LINKABLE资源[登录失败]: ")
			}

			for _, v := range account.Cookie {
				cookie := v
				webDownloadDriver.AddCookie(&cookie)
			}

		}

		//utils.RandomSleep()
		//
		////资源不能免费下载
		//crawledItem, err := webDownloadDriver.FindElement(selenium.ByXPATH, "//div[@id='crawled-part-form:crawled-part-dialog']//p[@class='Mtop1px']")
		//
		//if err == nil && crawledItem != nil {
		//	//这个资源不能免费下载
		//	crawledText, _ := crawledItem.Text()
		//	if strings.Contains(crawledText, "This catalog was") {
		//
		//		fmt.Println("这个资源不能免费下载")
		//		utils.RedisSetItemStatus(url, utils.URL_STATUS_UNCRAWLED)
		//		//删除文件夹
		//		err := os.RemoveAll(dir)
		//		if err != nil {
		//			fmt.Println("删除文件夹失败 : ", err)
		//		}
		//		return errors.New("这个资源不能免费下载")
		//	}
		//
		//}

		utils.RandomSleep()
		//topMessage-type
		//如果找了topMessage-type这个元素，说明今日没有下载次数了 直接终止循环

		script := `return document.getElementById("topMessage-detail").textContent;`
		topMessageItem, err := webDownloadDriver.ExecuteScript(script, nil)

		if err != nil {
			// 处理执行JavaScript代码的错误
			fmt.Println("执行JavaScript代码失败:", err)

		}
		if topMessageItem == "您没有有效票来生成CAD模型" {
			fmt.Println("topMessageItem : ", topMessageItem)
			fmt.Println("LINKABLE资源[今日下载次数已经用完!!!!!]: " + " url :" + url)
			utils.DelAccountFromRedis(account.Email)
			//utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
			//return errors.New("LINKABLE资源[今日下载次数已经用完!!!!!]: " + " url :" + url)
			account = LoginGetCookie()
			if account == nil {
				fmt.Println("LINKABLE资源[登录失败]: url:"+url, " account : ", account)
				utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
				return errors.New("LINKABLE资源[登录失败]: ")
			}

			for _, v := range account.Cookie {
				cookie := v
				webDownloadDriver.AddCookie(&cookie)
			}
		}

		utils.RandomSleep()

		titleXPath := fmt.Sprintf("//tbody[@id='CC10:catalog-table-grid_scrollableTbody']//tr[@data-ri='%d']//td", i)
		titleItems, err := webDownloadDriver.FindElements(selenium.ByXPATH, titleXPath)

		titleItem, err := titleItems[1].FindElement(selenium.ByXPATH, ".//img")
		titleText, err := titleItem.GetAttribute("alt")

		var ArticleDetail Detail

		ArticleDetail.Title = filepath.Join(path, titleText)
		ArticleDetail.Url = url

		downloadItems, _ := webDownloadDriver.FindElements(selenium.ByXPATH, "//table[@role='grid']//td[@role='gridcell']//div[@class='table']//div[@class='tr']//div[@class='td']")
	outer:
		for _, downloadItem := range downloadItems {

			nameItem, err := downloadItem.FindElement(selenium.ByXPATH, ".//span[@class='Fbold OvWrapAny']")

			if err != nil {
				fmt.Println("获取名称Item失败 err : ", err)
				utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
				return err
			}

			nameText, err := nameItem.Text()
			if err != nil {
				fmt.Println("391行报错nameItem err : ", err)
			}

			if strings.Contains(nameText, titleText) {

				fmt.Println("titleText : ", titleText)

				fmt.Println("nameText : ", nameText)

				downBtnItem, _ := downloadItem.FindElement(selenium.ByXPATH, ".//div[@class='tr']")
				downText, _ := downBtnItem.Text()

				if strings.Contains(downText, "不可以下载.") {
					fmt.Println("不可以下载")
					utils.RedisSetItemStatus(url, utils.URL_STATUS_UNCRAWLED)
					return errors.New("不可以下载")
				}

				zipHrefItem, err := downloadItem.FindElement(selenium.ByXPATH, ".//div[@class='tr']//a")
				zipHref, err := zipHrefItem.GetAttribute("href")
				fmt.Println("zipHref : ", zipHref)
				if err == nil && zipHref != "" {

					//redis查一下是否已经下载过了

					info, err := utils.GetArticleFromRedis(ArticleDetail.Title)
					if info != "" && err == nil {
						fmt.Println("LINKABLE资源[单个文件跳过下载]: " + " url :" + url + " 已经处理或正在处理中")
						isDownload = true

						continue
					}

					//filename := filepath.Join(dir, titleText)
					//err = utils.DownloadImageGrab(zipHref, filename)

					fmt.Println("LINKABLE资源[开始下载]: " + " url :" + url)

					err = zipHrefItem.Click()

					utils.RandomSleep()

					if err != nil {
						fmt.Println("LINKABLE资源[下载失败]: "+" url :"+url+" err : ", err)
						isDownload = false
						utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
						return err
					} else {

						fmt.Println("LINKABLE资源[下载完成]: " + " url :" + url)

						ArticleDetail.Img = filepath.Join(dir, titleText)

						//获取2D预览图 有下载文件之后才能去获取2D预览图
						var maxRetries = 5

						for i := 0; i < maxRetries; i++ {
							preview2dItems, err := webDownloadDriver.FindElements(selenium.ByXPATH, "//div[contains(@id,'PA12:j_id_4n_4_9_6_f_4_3_9_3')]//div")

							if err != nil || preview2dItems == nil {
								fmt.Println("没有可用的 2D 数据")
								continue outer
							}

							counts := len(preview2dItems)

							if counts == 0 {
								fmt.Println("没有可用的 2D 数据")
								continue outer
							}
							//拿最后一个
							preview2dItems[counts-1].MoveTo(0, 0)
							preview2dItems[counts-1].Click()

							//
							//preview2dItems[2].MoveTo(0, 0)
							//
							//preview2dItems[2].Click()

							// 等待一段时间后重试
							time.Sleep(3 * time.Second)

							// 检查某个按钮是否存在
							refreshButton, err := webDownloadDriver.FindElement(selenium.ByXPATH, "//span[@class='ui-button-icon-left ui-icon ui-c pcomicon pcomicon-refresh']")
							if refreshButton != nil && err == nil {
								// 某个按钮存在，退出循环
								break

							}
						}

						utils.RandomSleep()

						refreshButton, err := webDownloadDriver.FindElement(selenium.ByXPATH, "//span[@class='ui-button-icon-left ui-icon ui-c pcomicon pcomicon-refresh']")

						if err != nil {
							fmt.Println("refreshButton err : ", err)
						}
						refreshButton.Click()

						utils.RandomSleep()

						script2 := `return document.getElementById("topMessage-detail").textContent;`
						topMessageItem2, err := webDownloadDriver.ExecuteScript(script2, nil)

						if err != nil {
							// 处理执行JavaScript代码的错误
							fmt.Println("执行JavaScript代码失败:", err)

						}
						if strings.Contains(topMessageItem2.(string), "当前已达到下载限额，请参考许可协议中的使用条款。") {
							fmt.Println("topMessageItem : ", topMessageItem2)
							fmt.Println("LINKABLE资源[今日下载次数已经用完!!!!!]: " + " url :" + url)
							utils.DelAccountFromRedis(account.Email)
							//utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
							//return errors.New("LINKABLE资源[今日下载次数已经用完!!!!!]: " + " url :" + url)
							account = LoginGetCookie()
							if account == nil {
								fmt.Println("LINKABLE资源[登录失败]: url:"+url, " account : ", account)
								utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
								return errors.New("LINKABLE资源[登录失败]: ")
							}

							for _, v := range account.Cookie {
								cookie := v
								webDownloadDriver.AddCookie(&cookie)
							}

						}

						utils.RandomSleep()

						//找到并且进入iframe
						previewIframeViewerDivItem, err := webDownloadDriver.FindElement(selenium.ByXPATH, "//div[@class='previewIframeViewerDiv']")

						if err != nil {
							fmt.Println("previewIframeViewerDivItem err : ", err)
						}

						frame, err := previewIframeViewerDivItem.FindElement(selenium.ByXPATH, ".//iframe")
						if err != nil {
							fmt.Println("frame", err)

						}
						err = webDownloadDriver.SwitchFrame(frame)
						if err != nil {
							fmt.Println("SwitchFrame err : ", err)
						}

						//TODo: 下面就是在iframe里面操作了，记得操作完之后要切回来

						cnsWebViewerItem, err := webDownloadDriver.FindElement(selenium.ByID, "cnsWebViewer")

						html, _ := cnsWebViewerItem.GetAttribute("outerHTML")

						fmt.Println("html : ", html)

						svgItem, err := cnsWebViewerItem.FindElement(selenium.ByCSSSelector, "svg")

						if err != nil {
							fmt.Println("LINKABLE资源[没找到2D图纸]: "+" url :"+url+" err : ", err)
							isDownload = false
							utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
							return err
						}

						imgBase64, err := SvgToBase64(ArticleDetail, svgItem, webDownloadDriver)
						if err != nil {
							fmt.Println("LINKABLE资源[下载2D图失败]: "+" url :"+url+" err : ", err)
							isDownload = false
							utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)
							return err
						}

						// 切回主页面
						webDownloadDriver.SwitchFrame(nil)

						ArticleDetail.ImageBase64 = imgBase64
						text, _ := json.Marshal(ArticleDetail)
						utils.SetArticleToRedis(ArticleDetail.Title, gconv.String(text))
						isDownload = true

					}
				}

			}

		}

	}
	if isDownload {
		utils.RedisSetItemStatus(url, utils.URL_STATUS_CRAWLED)
	} else {
		utils.RedisSetItemStatus(url, utils.URL_STATUS_FAIL)

	}

	return nil

}

func SecondLevelList(url string, account *utils.Account) ([]string, []string, *utils.Account, error) {
	//account := LoginGetCookie()

	cookies := account.Cookie
	if cookies == nil {
		account = LoginGetCookie()

		if account == nil {
			fmt.Println("LINKABLE列表[登录失败]: url:"+url, " account : ", account)
			return nil, nil, nil, errors.New("LINKABLE列表[登录失败]: ")
		}

		cookies = account.Cookie
	}

	port := utils.RedisGetValidPort()
	_, webDriver, err := utils.GetWebDriver(utils.RedisGetValidPort())
	defer utils.RedisReleasePort(port)
	defer webDriver.Quit()
	if err != nil {
		fmt.Println("GetWebDriver err : ", err)
		log.Fatal("反爬虫机制触发,wait 10 minutes")

	}

	indexUrl := "https://linkable.partcommunity.com/3d-cad-models/sso/"
	err = webDriver.Get(indexUrl)
	if err != nil {
		fmt.Println("加载页面失败 : ", err)
	}

	for _, v := range cookies {
		cookie := v
		err = webDriver.AddCookie(&cookie)
		if err != nil {
			fmt.Println("AddCookie err : ", err)
		}
	}
	utils.RandomSleep()
	err = webDriver.Get(url)
	if err != nil {
		fmt.Println("加载页面失败 : ", err)
	}
	utils.RandomSleep()

	elements, err := webDriver.FindElements(selenium.ByXPATH, "//li[@class='item-list-element cns-underline-reveal alphabet-selection-element search-result-element']//a")
	if len(elements) == 0 {
		fmt.Println("没有登录成功。没找到二级列表")
		return nil, nil, nil, errors.New("没有登录成功。没找到二级列表")
	}

	var urls []string
	var secondLevelUrls []string
	var href string

	for _, element := range elements {
		href, err = element.GetAttribute("href")
		if err != nil {
			fmt.Println("获取链接失败 : ", err)
		}

		//如果得到的url包含.prj则是详情页 其他的都归属于二级列表

		if strings.Contains(href, ".prj") {
			//详情页
			//utils.RedisSetItemStatus(url, utils.URL_STATUS_PROCESSING)
			urls = append(urls, href)
		} else {
			//其他目录
			//utils.SetSecondLevelUrlToRedis(href, utils.URL_STATUS_PROCESSING)
			secondLevelUrls = append(secondLevelUrls, href)
		}

		//labelItem, _ := element.FindElement(selenium.ByXPATH, ".//span[@class='item-name']")
		//labelText, _ := labelItem.Text()
		//

	}

	account.Cookie, _ = webDriver.GetCookies()

	return urls, secondLevelUrls, account, nil
}

func SvgToBase64(ArticleDetail Detail, svgItem selenium.WebElement, wd selenium.WebDriver) (string, error) {
	// 执行JavaScript代码
	script := `
        // 获取要转换的SVG元素
   		//var svgElement = document.querySelector("svg");
        var svgElement = arguments[0];

        // 创建一个新的Image对象
        var img = new Image();

        // 创建一个新的Canvas元素
        var canvas = document.createElement('canvas');
        

		canvas.width = svgElement.clientWidth+500;
        canvas.height = svgElement.clientHeight+500;
		

        // 获取Canvas的2D上下文
        var ctx = canvas.getContext('2d');

        // 将SVG内容绘制到Canvas上
        var svgString = new XMLSerializer().serializeToString(svgElement);
        var DOMURL = window.URL || window.webkitURL || window;
        var svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
        var url = DOMURL.createObjectURL(svgBlob);
        img.onload = function() {
			// 计算图像在Canvas上的居中位置
			var x = (canvas.width - img.width) / 2;
			var y = (canvas.height - img.height) / 2;


            // 在Canvas上绘制图像
            ctx.drawImage(img, x, y);

            // 将Canvas转换为DataURL
            var dataUrl = canvas.toDataURL('image/png');
            console.log("dataUrl : ", dataUrl);


			// 创建一个隐藏的链接元素
			var link = document.createElement('img');
			link.src = dataUrl;
			link.download = 'image.png'; // 设置下载的文件名
			link.style.display = 'none';
		
			// 将链接元素添加到文档中并模拟点击
			document.body.appendChild(link);
			link.click();

        };
		
        img.src = url;
    `

	// 执行JavaScript代码，并将SVG元素作为参数传递给代码
	_, err := wd.ExecuteScript(script, []interface{}{svgItem})
	if err != nil {
		return "", err
	}

	utils.RandomSleep()
	// 等待一段时间，以便观察结果
	time.Sleep(5 * time.Second)

	imgItem, _ := wd.FindElement(selenium.ByCSSSelector, "img")
	imgSrc, _ := imgItem.GetAttribute("src")
	//fmt.Println("imgSrc : ", imgSrc)

	utils.RandomSleep()

	// Remove the data:image/png;base64, prefix from the base64 string
	base64String := strings.TrimPrefix(imgSrc, "data:image/png;base64,")

	// 解码Base64数据
	imageData, err := base64.StdEncoding.DecodeString(strings.TrimSpace(base64String))
	if err != nil {
		return "", err
	}

	// 创建图像对象
	img, _, err := image.Decode(strings.NewReader(string(imageData)))
	if err != nil {
		return "", err
	}

	// 创建输出文件路径
	outputPath := ArticleDetail.Img + ".png"
	outputPath = filepath.Clean(filepath.FromSlash(outputPath))

	// 创建输出文件目录
	err = os.MkdirAll(filepath.Dir(outputPath), os.ModePerm)
	if err != nil {
		return "", err
	}

	// 创建输出文件
	file, err := os.Create(outputPath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	// 将图像保存为PNG格式
	err = png.Encode(file, img)
	if err != nil {
		return "", err
	}

	// 输出成功消息
	println("PNG图像已保存到指定路径")

	fmt.Println("Image saved successfully.")

	return imgSrc, nil
}

// func GetLinkableDetail(url string) {
//
//	cookies := LoginGetCookie()
//
//	port := utils.RedisGetValidPort()
//	_, webDriver, err := utils.GetWebDriver(utils.RedisGetValidPort(), nil)
//	defer utils.RedisReleasePort(port)
//	defer webDriver.Quit()
//	if err != nil {
//		fmt.Println("GetWebDriver err : ", err)
//		log.Fatal("反爬虫机制触发,wait 10 minutes")
//
//	}
//
//	indexUrl := "https://linkable.partcommunity.com/3d-cad-models/sso/"
//	err = webDriver.Get(indexUrl)
//	if err != nil {
//		fmt.Println("加载页面失败 : ", err)
//	}
//
//	for _, v := range *cookies {
//		cookie := v
//		err = webDriver.AddCookie(&cookie)
//		if err != nil {
//			fmt.Println("AddCookie err : ", err)
//		}
//	}
//	utils.RandomSleep()
//
//	err = webDriver.Get(url)
//	if err != nil {
//		fmt.Println("加载页面失败 : ", err)
//	}
//	utils.RandomSleep()
//
//	cadButton, _ := webDriver.FindElement(selenium.ByXPATH, "//button[@id='CC10:j_id_4n_4_9_3_f_4_3_9_3e_b_2_2_2']")
//	cadButton.Click()
//
//	zipHrefItems, _ := webDriver.FindElement(selenium.ByXPATH, "//table[@role='grid']//td[@role='gridcell']//div[@class='table']//div[@class='tr']//div[@class='td']//div[@class='tr']//a")
//
//	zipHref, _ := zipHrefItems.GetAttribute("href")
//	fmt.Println("zipHref : ", zipHref)
//
// }
// Function to convert an image to JPEG format
func Test1() {
	port := utils.RedisGetValidPort()
	_, wd, err := utils.GetWebDriver(utils.RedisGetValidPort())
	defer utils.RedisReleasePort(port)
	defer wd.Quit()
	if err != nil {
		fmt.Println("GetWebDriver err : ", err)
		log.Fatal("反爬虫机制触发,wait 10 minutes")

	}
	wd.Get("file:///E:/goproject/linkable_spider/1.html")

	// 执行JavaScript代码
	script := `
        // 获取要转换的SVG元素

		var svgElement = document.querySelector("svg");

        // 创建一个新的Image对象
        var img = new Image();

        // 创建一个新的Canvas元素
        var canvas = document.createElement('canvas');
        canvas.width = svgElement.clientWidth;
        canvas.height = svgElement.clientHeight;

		console.log("svgElement.clientWidth : ", svgElement.clientWidth);
		console.log("svgElement.clientHeight : ", svgElement.clientHeight);

        // 获取Canvas的2D上下文
        var ctx = canvas.getContext('2d');

        // 将SVG内容绘制到Canvas上
        var svgString = new XMLSerializer().serializeToString(svgElement);
        var DOMURL = window.URL || window.webkitURL || window;
        var svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
        var url = DOMURL.createObjectURL(svgBlob);
        img.onload = function() {
            // 在Canvas上绘制图像
            ctx.drawImage(img, 0, 0);

            // 将Canvas转换为DataURL
            var dataUrl = canvas.toDataURL('image/png');

			// 创建一个新的image标签
			var newImg = document.createElement('img');
			newImg.src = dataUrl;
		
			// 将新的image标签添加到文档中
			document.body.appendChild(newImg);
		
			// 释放URL对象
			DOMURL.revokeObjectURL(url);
        };
        img.src = url;
    `
	_, err = wd.ExecuteScript(script, nil)
	if err != nil {
		log.Fatal("无法执行JavaScript代码:", err)
	}

	fmt.Println("转换成功！")
}

func Test() {
	port := utils.RedisGetValidPort()
	_, wd, err := utils.GetWebDriver(utils.RedisGetValidPort())
	defer utils.RedisReleasePort(port)
	if err != nil {
		fmt.Println("GetWebDriver err : ", err)
		log.Fatal("反爬虫机制触发,wait 10 minutes")
	}

	wd.Get("file:///E:/goproject/linkable_spider/1.html")

	var svgElement selenium.WebElement
	// 等待SVG元素加载完成
	wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) {
		svgElement, err = wd.FindElement(selenium.ByCSSSelector, "svg")
		if err != nil {
			return false, err
		}
		// 检查SVG元素是否已加载
		loaded, err := svgElement.IsDisplayed()
		if err != nil {
			return false, err
		}
		return loaded, nil
	}, 10*time.Second)

	svgElement, _ = wd.FindElement(selenium.ByCSSSelector, "svg")

	// 执行JavaScript代码
	script := `
        // 获取要转换的SVG元素

        var svgElement = document.querySelector("svg");

        // 创建一个新的Image对象
        var img = new Image();

        // 创建一个新的Canvas元素
        //var canvas = document.createElement('canvas');
        //canvas.width = svgElement.clientWidth;
        //canvas.height = svgElement.clientHeight;

		var canvas = document.createElement('canvas');
		canvas.width = 800; // 设置期望的宽度
		canvas.height = 600; // 设置期望的高度

        console.log("svgElement.clientWidth : ", svgElement.clientWidth);
        console.log("svgElement.clientHeight : ", svgElement.clientHeight);

        // 获取Canvas的2D上下文
        var ctx = canvas.getContext('2d');

        // 将SVG内容绘制到Canvas上
        var svgString = new XMLSerializer().serializeToString(svgElement);
        var DOMURL = window.URL || window.webkitURL || window;
        var svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
        var url = DOMURL.createObjectURL(svgBlob);
        img.onload = function() {
            // 在Canvas上绘制图像
            ctx.drawImage(img, 0, 0);

            // 将Canvas转换为DataURL
            var dataUrl = canvas.toDataURL('image/png');
			console.log("dataUrl : ", dataUrl);
			// 创建一个新的image标签
			var newImg = document.createElement('img');
			newImg.src = dataUrl;
			// 将img标签添加到DOM中
			document.body.appendChild(newImg);
		
        };
        img.src = url;
		console.log("url : ", url);
		console.log("newImg : ", newImg);

    `
	_, err = wd.ExecuteScript(script, []interface{}{svgElement})
	utils.RandomSleep()

	if err != nil {
		log.Fatal("无法执行JavaScript代码:", err)
	}

	utils.RandomSleep()

	imgItem, _ := wd.FindElement(selenium.ByCSSSelector, "img")
	imgSrc, _ := imgItem.GetAttribute("src")
	fmt.Println("imgSrc : ", imgSrc)

	wd.Quit()

	fmt.Println("转换成功！")
}

func TestSvg() {
	port := utils.RedisGetValidPort()
	_, wd, err := utils.GetWebDriverDownload(utils.RedisGetValidPort(), "E:/goproject/linkable_spider/")
	defer utils.RedisReleasePort(port)
	if err != nil {
		fmt.Println("GetWebDriver err : ", err)
		log.Fatal("反爬虫机制触发,wait 10 minutes")
	}

	wd.Get("file:///E:/goproject/linkable_spider/1.html")

	if err != nil {
		log.Fatal(err)
	}
	// 等待SVG元素加载完成
	_, err = wd.FindElement(selenium.ByCSSSelector, "svg")
	if err != nil {
		log.Fatal(err)
	}

	// 执行JavaScript代码
	script := `
        // 获取要转换的SVG元素
   		var svgElement = document.querySelector("svg");

        // 创建一个新的Image对象
        var img = new Image();

        // 创建一个新的Canvas元素
        var canvas = document.createElement('canvas');
        canvas.width = 900;
        canvas.height = 900;

        // 获取Canvas的2D上下文
        var ctx = canvas.getContext('2d');

        // 将SVG内容绘制到Canvas上
        var svgString = new XMLSerializer().serializeToString(svgElement);
        var DOMURL = window.URL || window.webkitURL || window;
        var svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
        var url = DOMURL.createObjectURL(svgBlob);
        img.onload = function() {
            // 在Canvas上绘制图像
            ctx.drawImage(img, 0, 0);

            // 将Canvas转换为DataURL
            var dataUrl = canvas.toDataURL('image/png');
            console.log("dataUrl : ", dataUrl);


			// 创建一个隐藏的链接元素
			var link = document.createElement('img');
			link.src = dataUrl;
			link.download = 'image.png'; // 设置下载的文件名
			link.style.display = 'none';
		
			// 将链接元素添加到文档中并模拟点击
			document.body.appendChild(link);
			link.click();

        };
		
        img.src = url;
    `

	// 执行JavaScript代码，并将SVG元素作为参数传递给代码
	_, err = wd.ExecuteScript(script, nil)
	if err != nil {
		log.Fatal("无法执行JavaScript代码:", err)
	}

	utils.RandomSleep()
	// 等待一段时间，以便观察结果
	time.Sleep(5 * time.Second)

	imgItem, _ := wd.FindElement(selenium.ByCSSSelector, "img")
	imgSrc, _ := imgItem.GetAttribute("src")
	fmt.Println("imgSrc : ", imgSrc)

	utils.RandomSleep()

	// Remove the data:image/png;base64, prefix from the base64 string
	base64String := strings.TrimPrefix(imgSrc, "data:image/png;base64,")

	// Decode the base64 string
	imageBytes, err := base64.StdEncoding.DecodeString(base64String)
	if err != nil {
		fmt.Println("Error decoding base64 string:", err)
		return
	}

	// Save the image to a file
	err = ioutil.WriteFile("image.png", imageBytes, 0644)
	if err != nil {
		fmt.Println("Error saving image:", err)
		return
	}

	fmt.Println("Image saved successfully.")

	// 打印图像的Base64编码

	wd.Quit()
}

func ExportExcel() {

	conn := g.Redis().Conn()
	defer conn.Close()
	values, err := redis.StringMap(conn.Do("HGETALL", utils.LINKABLE_ARTICLE))
	if err != nil {
		fmt.Println("LINKABLE[导出出错]", err)
	}
	arData := make([]*Detail, 0)

	for _, value := range values {
		ninjaInfo := &Detail{}
		err = json.Unmarshal(gconv.Bytes(value), ninjaInfo)
		if err != nil {
			fmt.Println("LINKABLE[导出出错]", err)
		}
		arData = append(arData, ninjaInfo)

	}
	f := excelize.NewFile()
	index, err := f.NewSheet("LINKABLE")
	if err != nil {
		fmt.Println("LINKABLE[导出出错]:" + err.Error())
		return
	}
	defer f.Close()
	f.SetCellValue("LINKABLE", "A1", "标题")

	for index, element := range arData {
		lineNumber := index + 2
		titleCell := fmt.Sprintf("A%d", lineNumber)

		f.SetCellValue("LINKABLE", titleCell, element.Title)
	}

	f.SetActiveSheet(index)
	fileName := fmt.Sprintf("LINKABLE_%s.xlsx", gtime.Now().Format("Ymd_His"))
	err = f.SaveAs(fileName)
	if err != nil {
		fmt.Println("LINKABLE[导出出错]:" + err.Error())
		return
	}

	fmt.Println("LINKABLE[导出成功]:" + fileName)
}
